#pragma once

#include "Common.hpp"
#include "TcpServer.hpp"
#include "Socket.hpp"
#include <unordered_map>
#include "Util.hpp"

using namespace SocketModule;
using namespace LogModule;

const std::string gspace = " ";        // 首行分割符
const std::string glinespace = "\r\n"; // 行分割符
const std::string glinesep = ": ";     // 请求报头键值分隔符

const std::string webroot = "./wwwroot";   // web根目录
const std::string homepage = "index.html"; // web主页
const std::string page_404 = "/404.html";  // 404页面

// Http 请求类
class HttpRequest
{
public:
    HttpRequest() : _is_interact(false) {}
    ~HttpRequest() {}

    // 序列化 -- 服务端不需要对请求进行序列化
    // 反序列化
    bool Deserialize(std::string &reqstr)
    {
        // 1. 提取请求行
        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, glinespace);
        // LOG(LogLevel::DEBUG) << "reqline: " << reqline;

        // 2. 对请求行进行反序列化
        ParseReqLine(reqline);
        if (_uri == "/")
            _uri = webroot + _uri + homepage; // ./wwwroot/index.html
        else
            _uri = webroot + _uri; // ./wwwroot/xxx/xx/x.html

        // LOG(LogLevel::DEBUG) << "_method: " << _method;
        // LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        // LOG(LogLevel::DEBUG) << "_version: " << _version;

        // 3. 处理 GET 方法页面交互的情况 -- 提取 uri 中用户输入的参数
        const std::string temp = "?";
        auto pos = _uri.find(temp);
        if (pos == std::string::npos)
        {
            return true; // 不需要交互直接返回 true
        }
        _args = _uri.substr(pos + temp.size());
        _uri = _uri.substr(0, pos);
        _is_interact = true;

        return true;
    }

    // 解析请求行
    void ParseReqLine(std::string &reqline)
    {
        // GET / HTTP/1.1
        std::stringstream ss(reqline); // 自动以空格为分割符
        ss >> _method >> _uri >> _version;
    }

    std::string Uri()
    {
        return _uri;
    }

    bool IsInteract()
    {
        return _is_interact;
    }

    std::string Args()
    {
        return _args;
    }

private:
    // http 请求协议的字段
    std::string _method;
    std::string _uri;
    std::string _version;

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;

    std::string _args;
    bool _is_interact;
};

// Http 应答类
class HttpResponse
{
public:
    HttpResponse() : _blankline(glinespace), _version("HTTP/1.1") {} // 默认应答版本为 1.1
    ~HttpResponse() {}

    // 设置应答状态码和状态码描述
    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        case 301:
            _desc = "Moved Permanently";
        case 302:
            _desc = "See Other";
        default:
            break;
        }
    }

    void SetHeader(const std::string &key, const std::string &value)
    {
        auto iter = _headers.find(key);
        if (iter != _headers.end())
            return;
        _headers.insert(std::make_pair(key, value));
    }

    void SetTargetFile(const std::string target)
    {
        _targetfile = target;
    }

    std::string Uri2Suffix(const std::string &targetfile)
    {
        // ./wwwroot/xxx/xx/x.html
        auto pos = targetfile.rfind(".");
        if (pos == std::string::npos)
            return "text/html";
        std::string suffix = targetfile.substr(pos); // .html
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == ".png")
            return "image/png";
        else
            return "";
    }

    void SetText(const std::string &t)
    {
        _text = t;
    }

    // 制作 http 应答
    bool MakeResponse()
    {
        // 1. 忽略某些请求并对某些请求重定向
        if (_targetfile == "./wwwroot/favicon.ico")
        {
            LOG(LogLevel::DEBUG) << "ignore: " << _targetfile << " source request";
            return false;
        }
        if (_targetfile == "./wwwroot/redir_test")
        {
            SetCode(301);
            SetHeader("Location", "https//www.qq.com/");
            return true;
        }
        // 2. 处理一般请求
        int filesize = 0;
        bool res = Util::ReadFileContent(_targetfile, &_text);
        if (!res) // 2.1 请求资源不存在，返回 404 状态码和 404 页面
        {
            _text = "";
            LOG(LogLevel::WARNING) << "client want to get: " << _targetfile << "but not found";
            SetCode(404);
            _targetfile = webroot + page_404;
        }
        else // 2.2 请求资源存在，返回 200 状态码和请求资源
        {
            LOG(LogLevel::DEBUG) << "read file: " << _targetfile;
            SetCode(200);
        }
        filesize = Util::FileSize(_targetfile);
        SetHeader("Content-Length", std::to_string(filesize));
        std::string suffix = Uri2Suffix(_targetfile);
        SetHeader("Content-Type", suffix);
        Util::ReadFileContent(_targetfile, &_text);
        return true;
    }
    // 序列化
    std::string Serialize()
    {
        std::string resp_status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;
        LOG(LogLevel::DEBUG) << "resp_status_line: " << resp_status_line;
        std::string resp_header;
        for (auto &header : _headers)
        {
            std::string line = header.first + glinesep + header.second + glinespace;
            resp_header += line;
        }
        return resp_status_line + resp_header + _blankline + _text;
    }

    // 反序列化 -- 服务端不需要对应答进行反序列化
    void Deserialize() {}

private:
    // http 应答协议的字段
    std::string _version;
    int _code;                // 状态码
    std::string _desc = "OK"; // 状态码描述

    std::unordered_map<std::string, std::string> _headers;
    std::string _blankline;
    std::string _text;

    std::string _targetfile;
};

using http_func_t = std::function<void(HttpRequest &req, HttpResponse &resp)>;

class Http
{
public:
    Http(uint16_t port) : tsvrp(std::make_unique<TcpServer>(port)) {}

    void HandlerHttpRequest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string httpreqstr;
        // 1. 从网络中获取请求报文, 并检查报文完整性
        int n = sock->Recv(&httpreqstr);
        std::cout << "##########################" << std::endl;
        std::cout << httpreqstr;
        std::cout << "##########################" << std::endl;
        if (n > 0)
        {
            HttpRequest req;
            HttpResponse resp;
            // 这里没有做报文完整性检查
            // 2. 对请求字符串进行反序列化，转化成结构化请求
            req.Deserialize(httpreqstr);

            // 3. 判断该请求是否需要交互
            if (req.IsInteract())
            {
                if (_route.find(req.Uri()) == _route.end())
                {
                    resp.SetCode(302);
                }
                else
                {
                    _route[req.Uri()](req, resp);
                    std::string response_str = resp.Serialize();
                    sock->Send(response_str);
                }
            }
            else
            {
                // 3. 构建应答
                resp.SetTargetFile(req.Uri());
                resp.MakeResponse();

                // 4. 将应答序列化发送到网络
                std::string response_str = resp.Serialize();
                sock->Send(response_str);
            }
        }
    }

    void Start()
    {
        tsvrp->Start([this](std::shared_ptr<Socket> &sock, InetAddr &client)
                     { this->HandlerHttpRequest(sock, client); });
    }

    // 用于使用交互时的方法
    void RegisterService(const std::string name, http_func_t h)
    {
        std::string key = webroot + name; // ./wwwroot/login
        auto iter = _route.find(key);
        if (iter == _route.end())
        {
            _route.insert(std::make_pair(key, h));
        }
    }

private:
    std::unique_ptr<TcpServer> tsvrp;
    std::unordered_map<std::string, http_func_t> _route;
};